﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using Medianamik.Core;
using Medianamik.Core.CodeGeneration;
using Medianamik.Core.Sugar;
using Medianamik.Globalization;
using Medianamik.UI.TypeManagement.Controls;

namespace Medianamik.UI.TypeManagement
{
    public partial class InterfacePropertyManagement : BasePage
    {
        #region Fields

        private Guid? _interfaceId;
        private Guid? _propertyId;

        #endregion

        #region Events

        protected void Page_Load(object sender, EventArgs e)
        {
            //Un des deux params doit etre présent
            //Un ou l'autre
            #region Param interfaceid / propertyid

            string strInterfaceid = Request.QueryString["interfaceid"];

            if (!StringHelper.IsGuid(strInterfaceid, ref _interfaceId)) // Édition d'une propriété
            {
                string strPropertyID = Request.QueryString["propertyid"];

                if (!StringHelper.IsGuid(strPropertyID, ref _propertyId) || CurrentProperty == null)
                {
                    Response.Redirect(ReturnUrl);
                }
            }
            else // Ajout d'une propriété
            {
                if (CurrentInterface == null)
                {
                    Response.Redirect(ReturnUrl);
                }
            }

            #endregion

            if (!IsPostBack)
            {
                LoadData();

                if (IsEdition)
                {
                    SetValues();
                }
            }
        }

        protected void ValidateUniqueInterfacePropertyName(object source, ServerValidateEventArgs args)
        {
            args.IsValid = true;
            Guid id;

            //Si c'est l'édition d'une propriété
            if (_propertyId.HasValue)
            {
                if (CurrentInterface.PropertyNameExists(InterfacePropertyName.Text, out id)
                    && !_propertyId.Value.Equals(id))
                    args.IsValid = false;
            }
            else //Nouvelle propriété
            {
                if (CurrentInterface.Properties.Any(prop =>
                    prop.Name.Equals(InterfacePropertyName.Text, StringComparison.OrdinalIgnoreCase)))
                    args.IsValid = false;
            }
        }

        protected void SaveButton_Click(object sender, EventArgs e)
        {
            if (IsValid)
            {
                var dataTypeId = new Guid(DataTypeChoice.SelectedValue);

                short? length = null;

                var name = NameChoicePlaceHolder.Visible ? NameChoice.SelectedValue : InterfacePropertyName.Text;

                Guid? primaryTypeId = null;

                if (LookupPlaceHolder.Visible)
                    primaryTypeId = new Guid(LookupTypeChoice.SelectedValue);

                if (LengthPlaceHolder.Visible)
                    length = short.Parse(Length.Text);

                if (IsEdition)
                {
                    CurrentProperty.Name = InterfacePropertyName.Text;
                    CurrentProperty.Description = InterfacePropertyDescription.Text;
                    CurrentProperty.DataTypeId = dataTypeId;
                    CurrentProperty.MaxLength = length;
                    CurrentProperty.PrimaryTypeID = primaryTypeId;
                }
                else
                {
                    _currentProperty = new NodeTypeInterfaceProperty(name,
                        InterfacePropertyDescription.Text, CurrentInterface.ID, dataTypeId, length,
                        primaryTypeId);
                    CurrentInterface.Properties.Add(_currentProperty);
                }

                NodeTypeManager.SaveInterface(CurrentInterface);

                if (Implementers.Count() > 0)
                {
                    var code = new CodeService();
                    code.GenerateView(CurrentInterface);
                }

                Translator.CreateResource("TypeManagement", CurrentProperty.ID + "_Label",
                    LabelTranslatorBox.Values);

                Response.Redirect(ReturnUrl);
            }
        }

        protected void DataTypeChoiceChanged(object sender, EventArgs e)
        {

            if (CurrentDataType.MustSpecifyLength)
            {
                if (!LengthPlaceHolder.Visible)
                {
                    LengthPlaceHolder.Visible = true;
                    Length.Text = "";
                }

                LookupPlaceHolder.Visible = false;
            }
            else
            {
                LookupPlaceHolder.Visible = CurrentDataType.ID.Equals(DataTypes.UniqueIdentifier);
                LengthPlaceHolder.Visible = false;
            }
        }

        protected void NameChoiceChanged(object sender, EventArgs e)
        {
            if (NameChoice.SelectedIndex == 0)
            {
                LengthPlaceHolder.Visible = false;
                DataTypePlaceHolder.Visible = false;
            }
            else
            {
                DataTypePlaceHolder.Visible = true;
                var property = CurrentInterface.EligibleProperties
                    .First(p => p.Name.Equals(NameChoice.SelectedValue));

                DataTypeChoice.SelectedValue = property.DataType.ID.ToString();
                DataTypeChoice.Enabled = false;
                LengthPlaceHolder.Visible = property.DataType.MustSpecifyLength;

                if (property.DataType.ID.Equals(DataTypes.UniqueIdentifier))
                {
                    LookupPlaceHolder.Visible = true;
                    LookupTypeChoice.SelectedValue = property.PrimaryTypeID.ToString();
                    LookupTypeChoice.Enabled = false;
                }
                else
                {
                    LookupPlaceHolder.Visible = false;
                    LookupTypeChoice.Enabled = true;
                }

                var minMaxLength = GetMinMaxLength();

                if (LengthPlaceHolder.Visible && minMaxLength != null)
                    Length.Text = minMaxLength.ToString();
            }
        }

        protected void ValidateInterfacePropertyLength(object source, ServerValidateEventArgs args)
        {
            args.IsValid = true;

            var minMaxLength = GetMinMaxLength();

            if (minMaxLength != null && short.Parse(Length.Text) < minMaxLength)
            {
                args.IsValid = false;
                InterfacePropertyLengthValidator.ErrorMessage =
                    Translator.Translate("Medianamik_TypeManagement", "InterfacePropertyLengthMustBeAtLeast") + " " +
                    minMaxLength;
            }
        }



        #endregion

        #region Properties

        private IEnumerable<NodeTypeInterfaceImplementation> _implementers;
        public IEnumerable<NodeTypeInterfaceImplementation> Implementers
        {
            get
            {
                if (_implementers == null)
                {
                    _implementers = NodeTypeManager.GetNodeTypes(CurrentInterface.ID);
                }

                return _implementers;
            }
        }

        private DataType _currentDataType;
        public DataType CurrentDataType
        {
            get
            {
                if (_currentDataType == null)
                    _currentDataType = ConfigManager.GetDataTypeById(new Guid(DataTypeChoice.SelectedValue));

                return _currentDataType;
            }
        }

        private NodeTypeInterfaceProperty _currentProperty;
        public NodeTypeInterfaceProperty CurrentProperty
        {
            get
            {
                if (_currentProperty == null && _propertyId.HasValue)
                {
                    if (CurrentInterface == null)
                    {
                        _currentProperty = NodeTypeManager.DeleteNodeTypeInterfaceProperty(_propertyId.Value);

                        if (_currentProperty != null)
                            _currentInterface = _currentProperty.Owner;
                    }
                    else
                        _currentProperty = CurrentInterface.Properties
                            .FirstOrDefault(p => p.ID.Equals(_propertyId.Value));
                }

                return _currentProperty;
            }
        }

        private NodeTypeInterface _currentInterface;
        public NodeTypeInterface CurrentInterface
        {
            get
            {
                if (_currentInterface == null && _interfaceId.HasValue)
                {
                    _currentInterface = NodeTypeManager.GetNodeTypeInterface(_interfaceId.Value);
                }

                return _currentInterface;
            }
        }

        private bool IsEdition
        {
            get
            {
                return _propertyId.HasValue;
            }
        }

        private string _returnUrl;
        public string ReturnUrl
        {
            get
            {
                if (_returnUrl == null)
                {
                    if (CurrentInterface == null)
                        _returnUrl = "interfacelist.aspx";
                    else
                        _returnUrl = "interfacepropertylist.aspx?interfaceid=" + CurrentInterface.ID;
                }

                return _returnUrl;
            }
        }

        private NodeType _currentLookupType;
        public NodeType CurrentLookupType
        {
            get
            {
                if (_currentLookupType == null && LookupTypeChoice.SelectedIndex > 0)
                {
                    _currentLookupType = NodeTypeManager.GetNodeType(new Guid(LookupTypeChoice.SelectedValue));
                }

                return _currentLookupType;
            }
        }

        #endregion

        #region Methods

        private short? GetMinMaxLength()
        {
            short? minMaxLength = null;

            if (CurrentDataType.MustSpecifyLength && Implementers.Count() > 0)
            {
                var lengths = Implementers.SelectMany(i => i.Owner.GetAllProperties()
                           .Where(
                           p =>
                           p.Name.Equals(NameChoice.SelectedValue,
                                         StringComparison.OrdinalIgnoreCase))
                           .Select(p => p.MaxLength));

                minMaxLength = lengths.OrderByDescending(l => l).FirstOrDefault();
            }

            return minMaxLength;
        }

        /// <summary>
        /// Affecte les valeurs aux champs de la page
        /// </summary>
        private void SetValues()
        {
            if (Implementers.Count() > 0)
            {
                InterfacePropertyName.Enabled = false;
                DataTypeChoice.Enabled = false;
                LookupTypeChoice.Enabled = false;
            }

            #region Name and description

            InterfacePropertyName.Text = CurrentProperty.Name;
            InterfacePropertyDescription.Text = CurrentProperty.Description;

            #endregion

            #region DataType

            DataTypeChoice.SelectedValue = CurrentProperty.DataTypeId.ToString();

            #endregion

            #region LookupType

            if (CurrentDataType.ID.Equals(DataTypes.UniqueIdentifier))
            {
                LookupPlaceHolder.Visible = true;
                LookupTypeChoice.SelectedValue = CurrentProperty.PrimaryTypeID.ToString();
            }

            #endregion

            #region Length

            //TODO: Empecher un length plus petit que le plus grand des Implementers

            if (CurrentDataType.MustSpecifyLength)
            {
                LengthPlaceHolder.Visible = true;
                Length.Text = CurrentProperty.MaxLength.ToString();
            }

            #endregion

            #region Translations

            LabelTranslatorBox.Values = Translator.GetResources("TypeManagement",
                CurrentProperty.ID + "_Label",
                ConfigManager.GetMedianamikCultures().Select(c => c.CultureInfo));

            #endregion
        }

        private void LoadData()
        {
            DataTypeChoice.DataSource = ConfigManager.GetAllDataTypes();
            DataTypeChoice.DataBind();
            DataTypeChoice.Items.Insert(0, "");

            if (NodeTypeManager.EligibleLookupTypes.Count() > 0)
            {
                DataTypeChoice.Items.Add(new ListItem("Lookup", DataTypes.UniqueIdentifier.ToString()));
                LookupTypeChoice.DataSource = NodeTypeManager.EligibleLookupTypes;
                LookupTypeChoice.DataBind();
                LookupTypeChoice.Items.Insert(0, "");
            }

            if (!IsEdition && Implementers.Count() > 0)
            {
                var eligibleProperties = CurrentInterface.EligibleProperties;

                if (eligibleProperties.Count() == 0) Response.Redirect(ReturnUrl);

                NameChoicePlaceHolder.Visible = true;
                NamePlaceHolder.Visible = false;
                NameChoice.DataSource = eligibleProperties;
                NameChoice.DataBind();
                NameChoice.Items.Insert(0, "");

                DataTypePlaceHolder.Visible = false;
            }
        }

        #endregion
    }
}
